<template><div><h2 id="mysql中like模糊查询如何优化" tabindex="-1"><a class="header-anchor" href="#mysql中like模糊查询如何优化"><span>MySQL中like模糊查询如何优化</span></a></h2>
<p>在MySQL中，<code v-pre>LIKE</code>模糊查询可能导致性能问题，特别是当使用通配符<code v-pre>%</code>开头时，因为这通常会导致全表扫描。以下方法可以帮助优化<code v-pre>LIKE</code>模糊查询：</p>
<ol>
<li><strong>合理使用索引</strong>
<strong>前缀匹配：</strong> 使用<code v-pre>LIKE prefix%</code>的形式，这种情况MySQL能够利用索引。</li>
</ol>
<div class="language-SQL line-numbers-mode" data-ext="SQL" data-title="SQL"><pre v-pre class="language-SQL"><code>SELECT * FROM users WHERE username LIKE '李%';
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>如果<code v-pre>username</code>字段有索引，前缀匹配会用到索引。</p>
<ol start="2">
<li><strong>使用反向索引</strong>
对于需要匹配后缀的情况(即<code v-pre>LIKE %sunffix</code>)，可以创建一个辅助列存储反转字符串，并给与此列进行前缀匹配。
<strong>创建反向字符串：</strong></li>
</ol>
<div class="language-SQL line-numbers-mode" data-ext="SQL" data-title="SQL"><pre v-pre class="language-SQL"><code>ALTER TABLE users ADD reversed_username VARCHAR(255);
UPDATE users SET reversed_username = REVERSE(username);
CREATE INDEX idx_reversed_username ON users(reversed_username);
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><ol start="3">
<li><strong>限制扫描范围</strong>
在LIKE查询中，如果可以通过其他条件进一步缩小搜索范围，请尽量加入这些条件。</li>
</ol>
<div class="language-SQL line-numbers-mode" data-ext="SQL" data-title="SQL"><pre v-pre class="language-SQL"><code>SELECT * FROM users WHERE age &gt; 18 and username LIKE '李%';
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><ol start="4">
<li>
<p><strong>使用缓存</strong>
如果相同的查询需要频繁执行，可以考虑在应用层实施缓存策略来减少数据库负载。</p>
</li>
<li>
<p><strong>使用专业工具</strong>
例如：Elasticsearch、Solr或者Sphinx等。</p>
</li>
</ol>
<h2 id="count-1-、count-与count-列名-的区别" tabindex="-1"><a class="header-anchor" href="#count-1-、count-与count-列名-的区别"><span>count(1)、count(*)与count(列名)的区别</span></a></h2>
<p>在SQL中，<code v-pre>COUNT()</code>函数用于统计行的数量。</p>
<ol>
<li><strong>COUNT(1)</strong>
<ul>
<li>功能：统计表中行的数量，包含所有行，不论行中的值是什么。</li>
<li>工作原理：每一行以<code v-pre>常数1</code>进行计算，及对于每一行都会计数一次，因此它的计算与<code v-pre>COUNT(*)</code>相同。</li>
<li>效率：在某些数据库视线中，<code v-pre>COUNT(1)</code>的性能可能与<code v-pre>COUNT(*)</code>相同，因为二者在功能上是等效。</li>
</ul>
</li>
<li><strong>COUNT(*)</strong>
<ul>
<li>功能：统计表中所有行的数量，包括所有列，无论列的值是否为NULL。</li>
<li>工作原理：按行统计时，不考虑列的具体值和数据类型。</li>
<li>效率：最常用的方法之一，特别是在InnoDB引擎中，<code v-pre>COUNT(*)</code>通常是最优的技术形式，因为它被优化为直接统计数据页上的数目。</li>
</ul>
</li>
<li><strong>COUNT(column_name)</strong>
<ul>
<li>功能：统计指定列中非NULL值的行数。</li>
<li>工作原理：只计数该列中有非NULL值的行。因此，如果某行<code v-pre>column_name</code>中的值为NULL，则不会计入总数。</li>
<li>效率：用于需要过滤掉NULL值时。</li>
</ul>
</li>
</ol>
<h2 id="sql用了函数一定会导致索引失效吗" tabindex="-1"><a class="header-anchor" href="#sql用了函数一定会导致索引失效吗"><span>SQL用了函数一定会导致索引失效吗</span></a></h2>
<p><strong>不一定</strong>
在MySQL中，当查询语句中对索引列使用某些函数时，确实可能导致索引失效，迫使数据库执行全表扫描。这是因为函数应用于列值后，数据库无法直接利用索引中储存的排序信息。不过，这并不意味着所有情况都会导致索引失效，具体取决于使用的函数类型和场景。以下是详细说明：</p>
<h4 id="常见会导致索引失效的情况" tabindex="-1"><a class="header-anchor" href="#常见会导致索引失效的情况"><span>常见会导致索引失效的情况：</span></a></h4>
<ol>
<li><strong>对索引列使用函数</strong>
<ul>
<li>如果在<code v-pre>WHERE</code>自居中对索引列应用了函数转换，例如<code v-pre>LOWER(column_name)</code>，会导致索引无法被使用。这是因为索引是基于原始值而构建的，函数改变了这些值。<div class="language-SQL line-numbers-mode" data-ext="SQL" data-title="SQL"><pre v-pre class="language-SQL"><code>SELECT * FROM users WHERE LOWER(username)='john';
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div></li>
<li>在这种情况下，可以考虑在应用层处理大小写不敏感的比较，或者在数据库中创建一个计算列(从MySQL5.7开始支持持久化生成列)、存储计算值并对其建立索引。</li>
</ul>
</li>
<li><strong>计算表达式</strong>
<ul>
<li>使用计算表达式，如<code v-pre>column_name +1</code>可能导致MySQL放弃使用索引。<div class="language-SQL line-numbers-mode" data-ext="SQL" data-title="SQL"><pre v-pre class="language-SQL"><code>SELECT * FROM users WHERE age + 10 &gt; 100;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div></li>
</ul>
</li>
</ol>
<h4 id="不会导致索引失效的情况" tabindex="-1"><a class="header-anchor" href="#不会导致索引失效的情况"><span>不会导致索引失效的情况：</span></a></h4>
<ol>
<li><strong>函数在索引范围之外使用</strong>
<ul>
<li>函数不在索引范围(即<code v-pre>WHERE</code>或<code v-pre>ON</code>条件)使用时，索引仍然有效。例如，在<code v-pre>SELECT</code>列表、<code v-pre>ORDER BY</code>、<code v-pre>GROUP BY</code>的地方使用函数通常不影响索引的使用。<div class="language-SQL line-numbers-mode" data-ext="SQL" data-title="SQL"><pre v-pre class="language-SQL"><code>SELECT UPPER(username) FROM users WHERE username = 'john';  --- 索引用于WHERE子句
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div></li>
</ul>
</li>
</ol>
<h4 id="优化建议" tabindex="-1"><a class="header-anchor" href="#优化建议"><span>优化建议：</span></a></h4>
<ul>
<li><strong>使用生成列：</strong> 如果定期需要函数值，可以考虑使用生成列来预计算值并索引它。</li>
</ul>
<div class="language-SQL line-numbers-mode" data-ext="SQL" data-title="SQL"><pre v-pre class="language-SQL"><code>    ALTER TABLE users ADD username_lower VARCHAR(255) GENERATED ALWAYS AS (LOWER(username)) STORED, ADD INDEX(username_lower);
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><ul>
<li><strong>在应用层处理：</strong> 在应用层而不是数据库处理某些需要函数的计算或转换。</li>
<li><strong>分析查询计划：</strong> 使用<code v-pre>EXPLAIN</code>语句分析和验证查询是否有效利用索引。</li>
</ul>
<h2 id="什么时候索引失效反而提升效率" tabindex="-1"><a class="header-anchor" href="#什么时候索引失效反而提升效率"><span>什么时候索引失效反而提升效率</span></a></h2>
<p>在大多数情况下，索引在查询中用于提高性能的，因为它们加速了数据查找。然而，有些特殊情况下，索引的使用会导致性能下降，索引失效反而可能提升查询效率。以下是一些列子：</p>
<ol>
<li><strong>小表查询</strong>
对于非常小的表，MySQL可能会选择全表扫描（忽略索引），因为全表扫描的开销可能比通过索引逐行查找还要低。在这种情况下，索引失效不会损害性能，反而简化了查询。</li>
<li><strong>读取大部分或所有行</strong>
当一个查询返回表中很大比例的行（如30%或更多）时，使用索引查找可能会耗时更多，因为数据库必须调回主数据也已读取完整记录。全表扫描可能更有效，因为它可以逐行顺序读取数据。</li>
<li><strong>低选择性索引</strong>
如果索引列的选择性非常低，例如一个布尔型字段，许多行有相同的值，那么依赖索引可能会产生不必要的开销。全表扫描可以避免索引的搜索和回表开销。</li>
<li><strong>频繁更新的表</strong>
对于包含大量更新操作的表，索引的维护成本可能相对较高。尤其是在频繁更新索引列时，通过避免使用或减少复杂的索引可以减轻写操作的负担。</li>
<li><strong>复杂查询的优化选择</strong>
对于复杂的多表连接查询，优化器有时候可能选择执行计划中不使用某个索引（或部分失效），以提高整体连接和计算效率。</li>
<li><strong>数据分布于优化器误判</strong>
在某些特性情况下，如果索引导致MySQL错误地估计数据分布或行数，手动禁用索引或提示优化器使用不同策略可能提升性能。</li>
</ol>
<h4 id="总结" tabindex="-1"><a class="header-anchor" href="#总结"><span>总结</span></a></h4>
<p>尽管索引通常用于加速查询，但优化器会根据多种因素（包括表的大小、索引选择性、查询条件等）来选择是否使用索引。有时，跳出索引进行直接扫描能提高查询效率。这通常取决于查询的特性和数据的分布，所以在尝试优化查询性能时，应通过测试评估不同执行计划的得失。使用<code v-pre>EXPLAIN</code>分析查询计划是了解并优化查询性能的有效手段。</p>
<h2 id="mysql的深度分页如何优化" tabindex="-1"><a class="header-anchor" href="#mysql的深度分页如何优化"><span>MySQL的深度分页如何优化</span></a></h2>
<p>在MySQL中，当涉及到深度分页时(offset较大)，性能可能会显著下降。这是因为MySQL需要扫描和跳过大量行才能达到所需的偏移量。这会导致大量的磁盘I/O和内存消耗，进而影响查询性能。以下是一些常用的优化深度分页的方法：</p>
<ol>
<li><strong>基于主键或唯一索引的优化</strong>
利用主键或唯一索引可以显著提高深度分页的效率，因为它们能够指向特定的行。
记录上次查询的最大ID（或其他唯一标识符），并以此为起点进行下一次查询。这种方法需要有连续的、唯一的列（如自增ID）以用于分页。<div class="language-SQL line-numbers-mode" data-ext="SQL" data-title="SQL"><pre v-pre class="language-SQL"><code>SELECT * FROM table_name WHERE id &gt; last_seen_id ORDER BY id ASC LIMIT page_size;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div></li>
<li><strong>使用子查询优化</strong>
通过子查询的方式，仅选择需要的记录ID，然后再通过这些ID提取完整记录。</li>
</ol>
<ul>
<li>子查询JOIN<div class="language-SQL line-numbers-mode" data-ext="SQL" data-title="SQL"><pre v-pre class="language-SQL"><code>SELECT t.* froM table_name t
JOIN (
    SELECT id FROM table_name ORDER BY id LIMIT offset,page_size
) sub ON t.id=sub.id;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div></li>
</ul>
<ol start="3">
<li><strong>覆盖索引</strong>
确保分页操作使用的查询能够被覆盖索引满足，从而减少回表（访问数据页）的次数。</li>
<li><strong>缓存机制</strong>
在应用层面实现结果集缓存，避免重复查询。例如，可以将分页结果缓存到Redis或Memcached中。</li>
<li><strong>视业务情况优化</strong>
根据特定业务需求，可能可以优化显示的逻辑。例如，一些应用可以通过取得一定范围内的结果并在客户端分页来减少数据库的负担。</li>
<li><strong>限制最大页数</strong>
限制应用程序中最大可翻页数，避免用户访问深度分页。提示数据太旧或已过时，要求用户进行新的查询。</li>
</ol>
<p>最后，可以通过使用<code v-pre>EXPLAIN</code>命令分析每个查询计划，以确保优化真正有效。</p>
<h2 id="truncate、delete、drop的区别" tabindex="-1"><a class="header-anchor" href="#truncate、delete、drop的区别"><span>truncate、delete、drop的区别</span></a></h2>
<p><code v-pre>TRUNCATE</code>、<code v-pre>DELETE</code>、<code v-pre>DROP</code>都是SQL中的数据操作语句，用于删除数据或表结构，但它们在功能、性能和使用场景上有显著的区别：</p>
<h4 id="truncate" tabindex="-1"><a class="header-anchor" href="#truncate"><span>TRUNCATE</span></a></h4>
<ul>
<li>用途：用于删除表中的所有数据，但保留表结构。</li>
<li>性能：比<code v-pre>DELETE</code>快，因为它通常不记录单独的行删除操作，也不触发行级触发器。</li>
<li>事务处理：在大多数数据库系统中，<code v-pre>TRUNCATE</code>被视为一个DDL操作而非DML操作。因此，它可能不能被回滚（但这依赖于数据库的实现，某些系统可能支持事务性的<code v-pre>TRUNCATE</code>）。</li>
<li>自然递增：自然递增的值会被重置。</li>
<li>触发器：不会激活行级触发器。</li>
<li>语法：</li>
</ul>
<div class="language-SQL line-numbers-mode" data-ext="SQL" data-title="SQL"><pre v-pre class="language-SQL"><code>TRUNCATE TABLE table_name;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h4 id="delete" tabindex="-1"><a class="header-anchor" href="#delete"><span>DELETE</span></a></h4>
<ul>
<li>用途：用于删除表中的指定行或所有数据，但保留表结构和约束。</li>
<li>性能：比<code v-pre>TRUNCATE</code>慢，特别是在处理大表时，因为它逐行记录删除操作，并能激活触发器。</li>
<li>事务处理：是一个DML操作，支持事务处理，可以在事务中回滚。</li>
<li>自然递增：自然递增的值会被重置。</li>
<li>触发器：激活行级触发器。</li>
<li>语法：</li>
</ul>
<div class="language-SQL line-numbers-mode" data-ext="SQL" data-title="SQL"><pre v-pre class="language-SQL"><code>DELETE FROM TABLE table_name WHERE condition;

--- 若要删除所有行但不重置自动递增：
DELETE FROM table_name;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="drop" tabindex="-1"><a class="header-anchor" href="#drop"><span>DROP</span></a></h4>
<ul>
<li>
<p>用途：用于删除整个表、数据库或其他数据库对象，包括其结构和数据。</p>
</li>
<li>
<p>性能：通常是立即操作，不可恢复。</p>
</li>
<li>
<p>事务处理：是一个DDL操作，不可回滚（具体依赖数据库系统）。</p>
</li>
<li>
<p>删除影响：删除表视会删除所有数据、索引、约束和权限信息。</p>
</li>
<li>
<p>语法：</p>
</li>
</ul>
<div class="language-SQL line-numbers-mode" data-ext="SQL" data-title="SQL"><pre v-pre class="language-SQL"><code>DROP TABLE table_name;
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h4 id="总结-1" tabindex="-1"><a class="header-anchor" href="#总结-1"><span>总结</span></a></h4>
<ul>
<li>TRUNCATE：快速清空表，但保留表结构。适用于需要清空但不删除表的场景。</li>
<li>DELETE：逐行删除数据，可以选择性删除某些记录。适用于只想删除部分数据的场景，且支持事务。</li>
<li>DROP：删除整个表定义及其所有数据。适用于不需要表结构或其数据的情况。</li>
</ul>
<h2 id="mysql-8的索引跳跃扫描是什么" tabindex="-1"><a class="header-anchor" href="#mysql-8的索引跳跃扫描是什么"><span>MySQL 8的索引跳跃扫描是什么</span></a></h2>
<p>MySQL中的索引跳跃扫描(Skip Scan)是一种优化策略，旨在<strong>提高在特定条件下对复合索引的利用效率</strong>。尽管MySQL并没有明确标记这项技术为&quot;Skip Scan&quot;功能，但通过其优化器的改进，特别是在MySQL 8.0.13及其以后的版本中，MySQL可以在某些条件下实现类似Skip Scan的效果。</p>
<h4 id="示例" tabindex="-1"><a class="header-anchor" href="#示例"><span>示例：</span></a></h4>
<table>
<thead>
<tr>
<th>ID</th>
<th>Department</th>
<th>Position</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Sales</td>
<td>Manager</td>
</tr>
<tr>
<td>2</td>
<td>Sales</td>
<td>Executive</td>
</tr>
<tr>
<td>3</td>
<td>HR</td>
<td>Manager</td>
</tr>
<tr>
<td>4</td>
<td>HR</td>
<td>Executive</td>
</tr>
<tr>
<td>5</td>
<td>IT</td>
<td>Manager</td>
</tr>
<tr>
<td>6</td>
<td>IT</td>
<td>Executive</td>
</tr>
</tbody>
</table>
<p>并且在表上有一个复合索引<code v-pre>(Department、Position)</code>。</p>
<h4 id="查询场景" tabindex="-1"><a class="header-anchor" href="#查询场景"><span>查询场景</span></a></h4>
<p>假设我们希望查找所有Manager职位的员工：</p>
<div class="language-SQL line-numbers-mode" data-ext="SQL" data-title="SQL"><pre v-pre class="language-SQL"><code>SELECT * FROM employees WHERE Position = 'Manager';
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h4 id="传统索引处理" tabindex="-1"><a class="header-anchor" href="#传统索引处理"><span>传统索引处理</span></a></h4>
<p>如果正常按索引<code v-pre>(Department、Position)</code>的顺序使用，理想情况下需要首先给出<code v-pre>Department</code>条件，以充分利用索引优势，但本查询并没有提供对<code v-pre>Department</code>的条件。</p>
<h4 id="跳跃扫描的优化实现-概念性" tabindex="-1"><a class="header-anchor" href="#跳跃扫描的优化实现-概念性"><span>跳跃扫描的优化实现（概念性）</span></a></h4>
<p>通过类似Skip Scan的逻辑，MySQL优化器可能会：</p>
<ol>
<li><strong>分区扫描</strong>
<ul>
<li>将索引按<code v-pre>Department</code>的唯一值进行分割。每个分区相当于不同的部门，比如<code v-pre>Sales</code>、<code v-pre>HR</code>、<code v-pre>IT</code>。</li>
</ul>
</li>
<li><strong>应用条件</strong>
<ul>
<li>对每个<code v-pre>Department</code>分区中的<code v-pre>Position</code>行进行扫描，即跳跃扫描中仅搜索<code v-pre>Position = 'Manager'</code>的员工。</li>
</ul>
</li>
<li><strong>跳过无关分区</strong>
<ul>
<li>由于<code v-pre>Position = 'Manager'</code>限定，我们只在每个<code v-pre>Department</code>的分区中寻找匹配的<code v-pre>Position</code>,而不是对整个表进行扫描。</li>
</ul>
</li>
</ol>
<h4 id="实际效果" tabindex="-1"><a class="header-anchor" href="#实际效果"><span>实际效果</span></a></h4>
<p>虽然MySQL索引跳跃扫描概念上并不是一个独立表示的特性，但此类索引优化策略在新版MySQL中可能通过改进的索引条件推送和查询优化器来实现。它潜在地减少读取和滤除不必要数据的开销。</p>
<p>这种策略在数据有较低基数(即<code v-pre>Department</code>的唯一值少)的场景中特别有效，因为跳跃的次数减少，提高了效率。可通过<code v-pre>EXPLAIN</code>检查特定查询的实际执行计划以确保优化的应用。</p>
<h2 id="mysql只操作同一条记录也会死锁吗" tabindex="-1"><a class="header-anchor" href="#mysql只操作同一条记录也会死锁吗"><span>MySQL只操作同一条记录也会死锁吗</span></a></h2>
<p>在MySQL中，即使多个事务仅对同一条记录进行操作，也有可能发生死锁。这通常与InnoDB存储引擎的锁管理机制有关。以下是一些触发这种情况的场景：</p>
<h4 id="可能的死锁原因" tabindex="-1"><a class="header-anchor" href="#可能的死锁原因"><span>可能的死锁原因：</span></a></h4>
<ol>
<li><strong>索引导致的所竞争</strong>
如果事务在WHERE子句中使用不同的索引来查找相同的行，InnoDB可能会导致多个事务以不同的顺序锁住这些索引，从而产生死锁。
<ul>
<li>示例：事务A、事务B同时对记录ID为1的行进行更新操作，且在不提交事务的情况下，都在等待对方持有的锁释放，就会导致产生死锁。</li>
</ul>
</li>
<li><strong>自增锁（auto-increment lock）</strong>
在使用自增列时，不同事务可能在等待获取表级锁来增加自增值，某些情况下也会出现死锁。</li>
<li><strong>外键约束</strong>
外键检查过程中可能涉及多个表，多个事务会因为不同的锁顺序而陷入死锁。</li>
</ol>
<h4 id="解决方法" tabindex="-1"><a class="header-anchor" href="#解决方法"><span>解决方法</span></a></h4>
<ol>
<li><strong>合适的索引和查询计划：</strong> 确保查询使用最优的索引，以减少锁的粒度。</li>
<li><strong>减少锁定时间：</strong> 尽量缩短事务的生命周期，避免在食物内进行过多的运算或等待。</li>
<li><strong>合理规划事务逻辑：</strong> 统一事务的锁定顺序，避免因为不同的顺序引起的锁等待。</li>
<li><strong>检测和重试：</strong> 配置合适的重试机制，当捕获死锁异常时重试事务操作。</li>
</ol>
<h2 id="为什么不建议使用存储过程" tabindex="-1"><a class="header-anchor" href="#为什么不建议使用存储过程"><span>为什么不建议使用存储过程</span></a></h2>
<p>存储过程是一种在数据库中为某些特定任务预编和存储的一组SQL语句，它们在某些应用场景中可以提高性能和提供便利。但它们也有一些局限和潜在的问题：</p>
<h4 id="原因和局限性" tabindex="-1"><a class="header-anchor" href="#原因和局限性"><span>原因和局限性：</span></a></h4>
<ol>
<li><strong>可移植性差：</strong> 存储过程通常是特定于数据库的，迁移到不同的数据库系统可能需要重写，阻碍了数据库灵活性。</li>
<li><strong>调试困难：</strong> 调试存储过程通常比调试应用层代码困难。许多开发工具不支持良好的调试功能，难以设置断点或逐步执行。</li>
<li><strong>版本控制挑战：</strong> 与代码库中的源代码不同，存储过程通常不易进行版本控制和团队协作，导致管理复杂性增加。</li>
<li><strong>复杂性和可读性：</strong> 大量的存储过程可能导致业务逻辑分散在数据库中，使得维护和阅读难度增加。尤其是在大型团队中，难以追踪和更新。</li>
<li><strong>性能问题：</strong> 在个别情况下，存储过程的运行性能可能由于数据库执行计划的限制或缓存策略不足而不如应用程序代码。</li>
</ol>
<h4 id="合适使用存储过程" tabindex="-1"><a class="header-anchor" href="#合适使用存储过程"><span>合适使用存储过程</span></a></h4>
<ul>
<li><strong>高性能需求：</strong> 当需要在数据库层进行复杂计算以减少网络往返时，存储过程能提供显著优势。</li>
<li><strong>复杂事务控制：</strong> 对数据库的复杂事务操作需要一致性和原子性，存储过程可更好地管理。</li>
<li><strong>业务规则集中管理：</strong> 在某些情况下，将部分业务逻辑下沉到数据库层可以集中管理复杂的数据库规则。</li>
<li><strong>多应用共享逻辑：</strong> 多个应用程序需要共享相同的数据库逻辑时，使用存储过程能确保一致性。</li>
</ul>
<h4 id="总结-2" tabindex="-1"><a class="header-anchor" href="#总结-2"><span>总结</span></a></h4>
<p>选择是否使用存储过程需要权衡系统需求、团队能力和维护复杂性等多个因素。在设计大型系统时，一般建议将存储过程仅用于特定场景，而非业务逻辑核心部分，保持数据库与应用之间的解耦以提高灵活性和可维护性。</p>
<h2 id="为什么mysql-8-0要取消查询缓存" tabindex="-1"><a class="header-anchor" href="#为什么mysql-8-0要取消查询缓存"><span>为什么MySQL 8.0要取消查询缓存</span></a></h2>
<p>主要是由于查询缓存在许多场景下带来的性能问题和复杂性。以下取消缓存的一些主要原因：</p>
<ol>
<li><strong>全局锁定问题：</strong> 查询缓存会在多用户环境中引发全局锁定问题。当一个表被修改时，相应的查询缓存需要被刷新，这会导致查询缓存的全局锁定，从而影响数据库的并发性能。</li>
<li><strong>竞争与争用：</strong> 在高并发环境中，由于查询缓存需要锁定来维持一致性，导致大量的竞争和锁争用。这种情况在写操作频繁和查询频繁的环境中尤为明显，因为每次写操作都可能触发缓存失效。</li>
<li><strong>维护与复杂性：</strong></li>
<li><strong>缓存命中率低：</strong></li>
<li><strong>替代方案的有效性：</strong></li>
<li><strong>复杂查询的支持：</strong></li>
</ol>
<h2 id="为什么大厂不建议使用多表join" tabindex="-1"><a class="header-anchor" href="#为什么大厂不建议使用多表join"><span>为什么大厂不建议使用多表join</span></a></h2>
<h4 id="常见的考虑因素" tabindex="-1"><a class="header-anchor" href="#常见的考虑因素"><span>常见的考虑因素：</span></a></h4>
<ol>
<li><strong>性能问题</strong>
<ul>
<li><strong>计算复杂性：</strong></li>
<li><strong>资源消耗：</strong></li>
<li><strong>索引依赖：</strong></li>
</ul>
</li>
<li><strong>可扩展性</strong>
<ul>
<li><strong>水平扩展挑战：</strong></li>
<li><strong>难以分片：</strong></li>
</ul>
</li>
<li><strong>维护与复杂度</strong>
<ul>
<li><strong>代码复杂性：</strong></li>
<li><strong>调试困难：</strong></li>
</ul>
</li>
<li><strong>架构设计</strong>
<ul>
<li><strong>领域模型割裂：</strong></li>
<li><strong>微服务架构限制：</strong></li>
</ul>
</li>
</ol>
<h4 id="替代策略" tabindex="-1"><a class="header-anchor" href="#替代策略"><span>替代策略</span></a></h4>
<p>为了避免使用多表JOIN，企业通常采取以下策略：</p>
<ul>
<li><strong>反范式化：</strong> 适当的冗余存储以减少JOIN需求。</li>
<li><strong>数据冗余：</strong> 在不同表中冗余存储一些公共字段，以避免频繁的JOIN。</li>
<li><strong>分而治之：</strong> 将复杂查询拆分为多个简单查询，在应用层进行数据组合。</li>
<li><strong>预先计算：</strong> 通过ETL作业预先计算和存储结果。</li>
<li><strong>使用NoSQL数据库：</strong> 设计生成系统时采用文档数据库或键值存储一类的NoSQL数据库来轻松支持复杂数据需求。</li>
</ul>
<p>这些方法有助于提高查询性能，减少延迟并增加系统的可拓展性。因此，大厂设计数据库和编写查询时，往往会尽量避免频繁和复杂的多表JOIN。</p>
<h2 id="区别度不高的字段索引一定没用吗" tabindex="-1"><a class="header-anchor" href="#区别度不高的字段索引一定没用吗"><span>区别度不高的字段索引一定没用吗</span></a></h2>
<h4 id="区别度不高的字段建索引的问题" tabindex="-1"><a class="header-anchor" href="#区别度不高的字段建索引的问题"><span>区别度不高的字段建索引的问题</span></a></h4>
<ol>
<li><strong>低效的过滤效果：</strong></li>
<li><strong>索引维护开销：</strong></li>
<li><strong>增大查询成本：</strong></li>
</ol>
<h4 id="何时低选择性索引可能有用" tabindex="-1"><a class="header-anchor" href="#何时低选择性索引可能有用"><span>何时低选择性索引可能有用</span></a></h4>
<ol>
<li><strong>固定值查询：</strong></li>
<li><strong>结合其他高选择性条件：</strong></li>
<li><strong>作为覆盖索引的一部分：</strong></li>
<li><strong>大数据集中的特定场合：</strong></li>
<li><strong>统计分析和报告</strong></li>
</ol>
<h2 id="mysql的行级锁-锁的到底是什么" tabindex="-1"><a class="header-anchor" href="#mysql的行级锁-锁的到底是什么"><span>MySQL的行级锁，锁的到底是什么</span></a></h2>
<p>MySQL的InnoDB存储引擎实现的行级锁，<strong>实际上锁定的是基于索引的行记录</strong>。这意味着，行锁针对的是数据库中的索引记录，而非数据表本身的物理行。这一关键特性有以下几个具体的表现：</p>
<h4 id="行级锁的锁定对象" tabindex="-1"><a class="header-anchor" href="#行级锁的锁定对象"><span>行级锁的锁定对象</span></a></h4>
<ol>
<li><strong>索引记录：</strong></li>
<li><strong>基于索引加锁：</strong></li>
</ol>
<h4 id="锁的运行和限制" tabindex="-1"><a class="header-anchor" href="#锁的运行和限制"><span>锁的运行和限制</span></a></h4>
<ol>
<li><strong>使用索引进行精确加锁：</strong></li>
<li><strong>锁冲突的减少：</strong></li>
<li><strong>隐式锁和显式锁：</strong></li>
</ol>
<h4 id="间隙锁和next-key锁" tabindex="-1"><a class="header-anchor" href="#间隙锁和next-key锁"><span>间隙锁和Next-key锁</span></a></h4>
<ol>
<li><strong>间隙锁（Gap Lock）：</strong></li>
<li><strong>Next-key Lock：</strong></li>
</ol>
<h2 id="where条件的顺序影响索引使用吗" tabindex="-1"><a class="header-anchor" href="#where条件的顺序影响索引使用吗"><span>where条件的顺序影响索引使用吗</span></a></h2>
<p>在MySQL中，<strong>WHERE条件的顺序确实可能影响索引的使用</strong>，尤其是在使用复合索引（多列索引）的情况下。然而<strong>这种影响主要取决于MySQL查询优化器的工作方式</strong>。而不是直接由WHERE子句中条件的书写顺序决定的。以下是一些关键点：</p>
<ol>
<li><strong>查询优化器的作用</strong>
<ul>
<li>MySQL的查询优化器通常会尝试重新排列WHERE条件以最优化索引的使用。</li>
<li>在大多数情况下，优化器能够独立于条件书写顺序来选择最佳的执行计划。</li>
</ul>
</li>
<li><strong>复合索引的最左前缀匹配原则</strong></li>
<li><strong>条件顺序与索引列顺序</strong></li>
<li><strong>范围条件的影响</strong>
<ul>
<li>在复合索引中，范围条件（如&gt;,&lt;,BETWEEN）之后的索引列通常不会被用于索引扫描。</li>
<li>因此，将等值条件（=）放在范围条件之前坑那个会更有效利用索引。</li>
</ul>
</li>
<li><strong>强制索引使用</strong>
<ul>
<li>在某些情况下，可以使用索引提示（如FORCE INDEX）来强制MySQL使用特定索引，但这种做法应谨慎使用。</li>
</ul>
</li>
<li><strong>验证索引使用</strong>
<ul>
<li>使用<code v-pre>EXPLAIN</code>命令可以查看MySQL如何执行查询，包括使用了哪些索引。</li>
</ul>
</li>
</ol>
<h4 id="最佳实践" tabindex="-1"><a class="header-anchor" href="#最佳实践"><span>最佳实践</span></a></h4>
<ol>
<li><strong>索引设计：</strong></li>
<li><strong>使用EXPLAIN：</strong></li>
<li><strong>优化器提示：</strong></li>
<li><strong>条件顺序：</strong></li>
<li><strong>范围条件考虑：</strong></li>
</ol>
<h2 id="为什么不推荐使用外键" tabindex="-1"><a class="header-anchor" href="#为什么不推荐使用外键"><span>为什么不推荐使用外键</span></a></h2>
<p>在许多数据库设计原则和项目中，尽管外键能够提供数据一致性和完整性约束，但在某些情况下，开发人员和数据库管理员可能会选择避免使用外键。以下是一些常见的原因：</p>
<ol>
<li><strong>性能影响</strong></li>
<li><strong>灵活性受限</strong></li>
<li><strong>复杂的管理</strong></li>
<li><strong>分布式系统的局限</strong></li>
<li><strong>应用层管理</strong></li>
<li><strong>数据库锁定问题</strong></li>
</ol>
<h4 id="何时使用外键" tabindex="-1"><a class="header-anchor" href="#何时使用外键"><span>何时使用外键</span></a></h4>
<ul>
<li><strong>明确的数据完整性需求</strong></li>
<li><strong>简单的数据模型</strong></li>
<li><strong>开发效率优先</strong></li>
</ul>
<h2 id="用了索引还是慢可能是什么原因" tabindex="-1"><a class="header-anchor" href="#用了索引还是慢可能是什么原因"><span>用了索引还是慢可能是什么原因</span></a></h2>
<h4 id="可能原因及解决方案" tabindex="-1"><a class="header-anchor" href="#可能原因及解决方案"><span>可能原因及解决方案</span></a></h4>
<ol>
<li><strong>索引不匹配查询：</strong></li>
<li><strong>数据分布不均：</strong></li>
<li><strong>索引的维护开销：</strong></li>
<li><strong>查询的非优化部分：</strong></li>
<li><strong>硬件资源限制：</strong></li>
<li><strong>表和索引的统计信息过期：</strong></li>
<li><strong>锁争用：</strong></li>
<li><strong>不当的表设计：</strong></li>
</ol>
<h4 id="进一步分析" tabindex="-1"><a class="header-anchor" href="#进一步分析"><span>进一步分析</span></a></h4>
<ol>
<li><strong>使用<code v-pre>SHOW INDEX FROM table_name</code> 查看当前索引</strong>，确保索引按预期创建。</li>
<li><strong>使用<code v-pre>EXPLAIN</code>分析特定查询</strong>，查看MySQL如何执行查询（执行计划）。</li>
<li><strong>监控系统资源</strong>，例如使用工具如<code v-pre>top</code>,<code v-pre>iostat</code>,以及数据库特有工具如<code v-pre>SHOW STATUS</code>。</li>
<li><strong>评估操作日志和慢日志日志</strong>，找出哪些查询消耗了大部分资源。</li>
</ol>
<h2 id="索引失效的问题如何排查" tabindex="-1"><a class="header-anchor" href="#索引失效的问题如何排查"><span>索引失效的问题如何排查</span></a></h2>
<ol>
<li><strong>使用EXPLAIN诊断查询</strong>
<ul>
<li><strong>分析查询执行计划：</strong></li>
</ul>
</li>
<li><strong>常见索引失效的原因</strong>
<ul>
<li><strong>函数和表达式：</strong></li>
<li><strong>前导模糊查询：</strong></li>
<li><strong>不等式条件</strong></li>
<li><strong>范围条件的影响：</strong></li>
</ul>
</li>
<li><strong>优化查询结构</strong>
<ul>
<li><strong>改写条件：</strong></li>
<li><strong>运用等效替代：</strong></li>
</ul>
</li>
<li><strong>检查索引和表设计</strong>
<ul>
<li><strong>审查索引的设计：</strong></li>
<li><strong>数据类型匹配：</strong></li>
</ul>
</li>
<li><strong>数据库配置和统计信息</strong>
<ul>
<li><strong>更新统计信息：</strong></li>
<li><strong>检查连接参数：</strong></li>
</ul>
</li>
<li><strong>限制和事务问题</strong>
<ul>
<li><strong>死锁和锁问题：</strong></li>
<li><strong>事务隔离级别：</strong></li>
</ul>
</li>
</ol>
<h2 id="如何进行sql调优" tabindex="-1"><a class="header-anchor" href="#如何进行sql调优"><span>如何进行SQL调优</span></a></h2>
<ol>
<li><strong>分析查询性能</strong>
<ul>
<li><strong>使用查询分析工具：</strong></li>
<li><strong>查看执行时间：</strong></li>
</ul>
</li>
<li><strong>合理使用索引</strong>
<ul>
<li><strong>创建适当的索引：</strong></li>
<li><strong>避免过多索引：</strong></li>
<li><strong>优化复合索引：</strong></li>
</ul>
</li>
<li><strong>重写SQL语句</strong>
<ul>
<li><strong>简化查询条件:</strong></li>
<li><strong>使用<code v-pre>JOIN</code>替代子查询:</strong></li>
<li><strong>避免<code v-pre>SELECT *</code> :</strong></li>
</ul>
</li>
<li><strong>优化数据模型</strong>
<ul>
<li><strong>规范化与反规范化：</strong></li>
<li><strong>使用合适的数据类型：</strong></li>
</ul>
</li>
<li><strong>缓存和批量操作</strong>
<ul>
<li><strong>缓存常用查询：</strong></li>
<li><strong>批量数据操作：</strong></li>
</ul>
</li>
<li><strong>更新和维护数据库</strong>
<ul>
<li><strong>定期重建索引：</strong></li>
<li><strong>更新统计信息：</strong></li>
</ul>
</li>
<li><strong>分布式和分区策略</strong>
<ul>
<li><strong>表分区或分片：</strong></li>
<li><strong>负载均衡：</strong></li>
</ul>
</li>
<li><strong>数据库和硬件优化</strong>
<ul>
<li><strong>调整数据库配置</strong></li>
<li><strong>硬件优化：</strong></li>
</ul>
</li>
</ol>
<h2 id="mysql索引设计有那些原则" tabindex="-1"><a class="header-anchor" href="#mysql索引设计有那些原则"><span>MySQL索引设计有那些原则</span></a></h2>
<ol>
<li><strong>选择合适的列</strong>
<ul>
<li><strong>频繁作为查询条件的列：</strong></li>
<li><strong>参与排序的列</strong></li>
<li><strong>作为连接条件的列：</strong></li>
</ul>
</li>
<li><strong>优化多列索引</strong>
<ul>
<li><strong>复合索引</strong></li>
<li><strong>最左前缀原则</strong></li>
</ul>
</li>
<li><strong>控制索引的数量和类型</strong>
<ul>
<li><strong>避免过多索引:</strong></li>
<li><strong>适用索引类型:</strong></li>
</ul>
</li>
<li><strong>考虑数据分布和选择性</strong>
<ul>
<li><strong>高选择性的列：</strong></li>
<li><strong>均匀分布的数据：</strong></li>
</ul>
</li>
<li><strong>避免冗余和重复索引</strong>
<ul>
<li><strong>合并索引：</strong></li>
<li><strong>定期清理：</strong></li>
</ul>
</li>
<li><strong>使用覆盖索引</strong>
<ul>
<li><strong>覆盖索引：</strong></li>
</ul>
</li>
<li><strong>关注变更和维护</strong>
<ul>
<li><strong>更新和插入的影响：</strong></li>
<li><strong>统计信息的刷新：</strong></li>
</ul>
</li>
<li><strong>考虑分区和分片</strong>
<ul>
<li><strong>大数据集的优化：</strong></li>
</ul>
</li>
</ol>
<h2 id="innodb加索引的时候会锁表吗" tabindex="-1"><a class="header-anchor" href="#innodb加索引的时候会锁表吗"><span>InnoDB加索引的时候会锁表吗</span></a></h2>
<ol>
<li><strong>添加索引时</strong>
<ul>
<li><strong>在线添加索引（Online DDL）：</strong> 不会锁住整张表，可以同时进行读取和写入操作。</li>
<li><strong>锁级别：</strong></li>
</ul>
</li>
<li><strong>删除索引</strong>
<ul>
<li>删除索引操作通常不需要长时间锁表，但在删除过程中可能进行短暂的锁定以保证元数据更新的一致性。</li>
</ul>
</li>
<li><strong>修改索引</strong>
<ul>
<li>对于某些索引修改，可能会引发锁表现象。</li>
</ul>
</li>
<li><strong>操作期间的锁定影响</strong></li>
</ol>
<h2 id="mysql默认隔离级别是rr-大厂为什么要改成rc" tabindex="-1"><a class="header-anchor" href="#mysql默认隔离级别是rr-大厂为什么要改成rc"><span>MySQL默认隔离级别是RR，大厂为什么要改成RC</span></a></h2>
<ol>
<li><strong>更高的并发性能：</strong></li>
<li><strong>降低锁等待与死锁概率：</strong></li>
<li><strong>较低的隔离级别适应性：</strong></li>
<li><strong>简化应用架构：</strong></li>
<li><strong>数据库和缓存系统的协同：</strong></li>
<li><strong>减少事务开销</strong></li>
</ol>
<h2 id="mysql为什么默认使用的是rr隔离级别" tabindex="-1"><a class="header-anchor" href="#mysql为什么默认使用的是rr隔离级别"><span>MySQL为什么默认使用的是RR隔离级别</span></a></h2>
<ol>
<li><strong>一致性保证：</strong></li>
<li><strong>防止&quot;幻读&quot;：</strong></li>
<li><strong>性能权衡：</strong></li>
<li><strong>可重复读取：</strong></li>
<li><strong>锁机制的优化：</strong></li>
<li><strong>广泛的应用和标准：</strong></li>
<li><strong>综合考量：</strong></li>
</ol>
<h2 id="数据库三大范式是什么" tabindex="-1"><a class="header-anchor" href="#数据库三大范式是什么"><span>数据库三大范式是什么</span></a></h2>
<p>数据库三大范式是关系型数据库设计中的一组规范，旨在提高数据结构的合理性、减少数据冗余和提高数据操作的效率。它们分别是：</p>
<ul>
<li><strong>第一范式（1NF）：</strong> 确保<strong>每个数据列都是不可再分的原子值</strong>，即每个单元格只包含一个值。这可以通过将表拆分为更小的表来实现，每个表都包含一个实体的属性。</li>
<li><strong>第二范式（2NF）：</strong> 建立在第一范式额度基础上，<strong>要求表中的每个非主键列完全依赖于主键列</strong>，而不是依赖于其他非主键列。换句话说，每个表应该只描述一个实现的信息。如果有部分信息依赖于表中的一部分主键，那么需要将这些信息拆分到另一个表中。</li>
<li><strong>第三范式（3NF）：</strong> 在第二范式的基础上，<strong>要求表中的每个非主键列之间不应该存在传递依赖关系</strong>。也就是说，非主键列之间不应该相互依赖，而是直接依赖于主键列。如果存在传递依赖，需要将其转换为直接依赖关系。</li>
</ul>
<p>这三个范式是逐步规范化设计数据库的步骤，目的是<strong>提高数据的一致性、完整性和减少冗余</strong>，从而<strong>提高数据库的性能和可维护性</strong>。但要注意，范式化设计并不是一成不变的，根据具体的业务需求和应用场景，有时候也需要对范式进行适度的调整和冗余处理。</p>
<h2 id="mysql为什么默认引擎是innodb" tabindex="-1"><a class="header-anchor" href="#mysql为什么默认引擎是innodb"><span>MySQL为什么默认引擎是InnoDB</span></a></h2>
<ol>
<li><strong>支持事务：</strong></li>
<li><strong>并发控制：</strong></li>
<li><strong>外键约束：</strong></li>
<li><strong>崩溃恢复：</strong></li>
<li><strong>支持热备份：</strong></li>
</ol>
<h2 id="什么是索引-索引有哪些优缺点" tabindex="-1"><a class="header-anchor" href="#什么是索引-索引有哪些优缺点"><span>什么是索引？索引有哪些优缺点？</span></a></h2>
<p>索引是数据库中用于<strong>提高数据检索性能的排好序的数据结构</strong>。
<strong>索引的优点：</strong>
- <strong>提高查询性能：</strong>
- <strong>唯一性约束：</strong>
<strong>索引的缺点：</strong>
- <strong>占用存储空间：</strong>
- <strong>索引维护的开销：</strong></p>
<h2 id="mysql索引分类" tabindex="-1"><a class="header-anchor" href="#mysql索引分类"><span>MySQL索引分类？</span></a></h2>
<ul>
<li><strong>主键索引</strong></li>
<li><strong>唯一索引</strong></li>
<li><strong>普通索引</strong></li>
<li><strong>复合索引</strong></li>
</ul>
<h2 id="myisam索引与innodb索引的区别" tabindex="-1"><a class="header-anchor" href="#myisam索引与innodb索引的区别"><span>MyISAM索引与InnoDB索引的区别</span></a></h2>
<ol>
<li><strong>存储方式：</strong></li>
<li><strong>锁机制：</strong></li>
<li><strong>事务支持：</strong></li>
<li><strong>引用完整性：</strong></li>
<li><strong>性能特点：</strong></li>
</ol>
<h2 id="创建索引时需要注意什么" tabindex="-1"><a class="header-anchor" href="#创建索引时需要注意什么"><span>创建索引时需要注意什么？</span></a></h2>
<ol>
<li><strong>选择适当的列：</strong></li>
<li><strong>避免过度的索引：</strong></li>
<li><strong>考虑联合索引：</strong></li>
<li><strong>注意索引的顺序：</strong></li>
<li><strong>使用合适的数据类型：</strong></li>
</ol>
<h2 id="什么时候不要使用索引" tabindex="-1"><a class="header-anchor" href="#什么时候不要使用索引"><span>什么时候不要使用索引？</span></a></h2>
<ul>
<li><strong>小型表：</strong></li>
<li><strong>插入和更新和删除频繁的表：</strong></li>
<li><strong>查询条件不经常使用：</strong></li>
<li><strong>需要频繁更新索引的表：</strong></li>
</ul>
<h2 id="mysql中有哪几种锁" tabindex="-1"><a class="header-anchor" href="#mysql中有哪几种锁"><span>MySQL中有哪几种锁？</span></a></h2>
<ol>
<li><strong>表级锁（Table-level Locking）：</strong></li>
<li><strong>共享锁（Shared Lock）：</strong></li>
<li><strong>排他锁（Exclusive Lock）：</strong></li>
<li><strong>行级锁（Row-level Locking）：</strong></li>
<li><strong>记录锁（Record Lock）：</strong></li>
<li><strong>间隙锁（Gap Lock）：</strong></li>
<li><strong>临减锁（Next-Key Lock）：</strong></li>
</ol>
<h2 id="b树和b-树的区别" tabindex="-1"><a class="header-anchor" href="#b树和b-树的区别"><span>B树和B+树的区别？</span></a></h2>
<ol>
<li><strong>数据存储方式：</strong></li>
<li><strong>数据检索方式：</strong></li>
<li><strong>范围查询效率：</strong></li>
<li><strong>适用场景：</strong></li>
</ol>
<h2 id="mysql中的in和exists的区别" tabindex="-1"><a class="header-anchor" href="#mysql中的in和exists的区别"><span>MySQL中的in和exists的区别</span></a></h2>
<ol>
<li><strong>IN 关键字</strong></li>
<li><strong>EXISTS 关键字</strong></li>
</ol>
<h2 id="mysql多表查询时有哪些连接方式" tabindex="-1"><a class="header-anchor" href="#mysql多表查询时有哪些连接方式"><span>MySQL多表查询时有哪些连接方式？</span></a></h2>
<ol>
<li><strong>内连接（INNER JOIN）：</strong></li>
<li><strong>左外连接（LEFT JOIN）：</strong></li>
<li><strong>右外连接（RIGHT JOIN）：</strong></li>
<li><strong>全外连接（FULL JOIN）：</strong></li>
<li><strong>自连接（SELF JOIN）：</strong></li>
<li><strong>交叉连接（CROSS JOIN）：</strong></li>
</ol>
<h2 id="什么是最左前缀原则" tabindex="-1"><a class="header-anchor" href="#什么是最左前缀原则"><span>什么是最左前缀原则？</span></a></h2>
<p>最左前缀原则（Leftmost Prefix Rule）是索引在数据库查询中的一种使用规则。它指的是在使用复合索引是，索引的最左边的连续几个列会被用于查询过滤条件的匹配。</p>
<p>遵循最左前缀原则的好处包括：</p>
<ol>
<li><strong>提高查询性能：</strong></li>
<li><strong>减少索引占用空间：</strong></li>
</ol>
<h2 id="什么是覆盖索引" tabindex="-1"><a class="header-anchor" href="#什么是覆盖索引"><span>什么是覆盖索引？</span></a></h2>
<p>覆盖索引是指一个索引包含了查询所需的列，而无需访问表的实际数据页。</p>
<p><strong>覆盖索引通常用于以下场景：</strong></p>
<ol>
<li>查询语句只需要返回索引列中的数据，而不需要访问其他列的值。</li>
<li>查询语句中的条件过滤、排序或分组的列都在同一个索引上。</li>
</ol>
<h2 id="为什么要索引下推" tabindex="-1"><a class="header-anchor" href="#为什么要索引下推"><span>为什么要索引下推？</span></a></h2>
<p>索引下推（Index Condition Pushdown,ICP）是MySQL优化器的意向优化技术，旨在提高通过索引检索数据的效率，尤其是在InnoDB存储引擎汇总。这项技术在MySQL5.6中引入，专门用于减少从表中读取不必要的行，提高查询性能。</p>
<h4 id="工作原理" tabindex="-1"><a class="header-anchor" href="#工作原理"><span>工作原理</span></a></h4>
<p>在没有索引下推的情况下，当查询使用复合索引时，MySQL可能需要访问主表来评估不能完全通过索引条件确定的行。例如，如果只有索引的部分条件在索引中能够被使用，而其他条件需要读取实际行再进行筛选，传统方式可能会导致更多的全行读取。</p>
<p>通过索引下推优化，MySQL可以在索引级别应用更多的查询过滤条件，从而减少读取主表的行数。</p>
<h4 id="优势" tabindex="-1"><a class="header-anchor" href="#优势"><span>优势</span></a></h4>
<ul>
<li><strong>减少I/O操作：</strong></li>
<li><strong>提高查询效率：</strong></li>
<li><strong>更快的响应时间：</strong></li>
</ul>
<h2 id="为什么需要数据库连接池" tabindex="-1"><a class="header-anchor" href="#为什么需要数据库连接池"><span>为什么需要数据库连接池？</span></a></h2>
<ol>
<li><strong>提高性能</strong></li>
<li><strong>资源管理</strong></li>
<li><strong>并发处理</strong></li>
<li><strong>连接可靠性</strong></li>
</ol>
<h2 id="并发事务带来哪些问题" tabindex="-1"><a class="header-anchor" href="#并发事务带来哪些问题"><span>并发事务带来哪些问题？</span></a></h2>
<ol>
<li><strong>脏读（Dirty Read）：</strong> 一个事务读取到另一个事务未提交的数据。假设事务A修改了一条数据但未提交，事务B却读取了这个未提交的数据，导致事务B基于不准确的数据做出了错误的决策。</li>
<li><strong>不可重复读（Non-repeatable Read）：</strong> 一个事务在多次读取同一条数据时，得到不同的结果。假设事务A读取了一条数据，事务B修改或删除了该数据并提交，然后事务A再次读取统一数据，发现与之前的读取结果不一致，造成数据的不一致性。</li>
<li><strong>幻读（Phantom Read）：</strong> 一个事务在多次查询同一范围的数据时，得到了不同数量的结果。假设事务A根据某个条件查询了一组数据，事务B插入了复合该条件的新数据并提交，然后事务A再次查询同一条件下的数据，发现结果集发生了变化，产生了幻觉般的新增数据。</li>
<li><strong>丢失修改（Lost Update）：</strong> 两个或多个事务同时修改同意数据，并且最终只有一个事务的修改被保留，其他事务的修改被覆盖或丢失。这种情况可能会导致数据的部分更新丢失，造成数据的不一致。</li>
</ol>
<p>不可重复读和幻读的区别：
不可重复读的重点是修改，比如多次读取一条记录发现其中某些列的值被修改；
幻读的重点在于新增或删除，比如多次读取一条记录发现记录增多或减少了。</p>
<h2 id="mysql记录货币用什么字段类型" tabindex="-1"><a class="header-anchor" href="#mysql记录货币用什么字段类型"><span>MySQL记录货币用什么字段类型</span></a></h2>
<p>一般推荐使用<code v-pre>DECIMAL</code>字段类型。</p>
<h2 id="char和varchar的区别" tabindex="-1"><a class="header-anchor" href="#char和varchar的区别"><span>CHAR和VARCHAR的区别</span></a></h2>
<ol>
<li><strong>存储方式：</strong> CHAR是固定长度的字符类型，而VARCHAR是可变长度的字符类型。</li>
<li><strong>占用空间：</strong> CHAR会以固定的长度存储数据，不论实际存储的字符数目，而VARCHAR则根据实际需要的空间动态分配存储。</li>
<li><strong>尾随空格：</strong> CHAR在存储时会用空格填充到执行长度，并在检索时需要删除尾随空格，而VARCHAR则不需要。</li>
<li><strong>长度限制：</strong> CHAR的长度范围为1到255个字符，而VARCHAR的长度范围也是255个字符，但可以根据需求设计更长的长度。</li>
<li><strong>访问效率：</strong> 由于CHAR是固定长度的，它在某些情况下可能会比VARCHAR稍微快一些。</li>
</ol>
<h2 id="union和union-all的区别" tabindex="-1"><a class="header-anchor" href="#union和union-all的区别"><span>UNION和UNION ALL的区别</span></a></h2>
<p><strong>UNION：</strong> UNION用于合并两个或多个查询结果集，并去除重复的行。在执行UNION操作时，数据库会进行额外的去重操作，这可能会带来一定的性能开销。
<strong>UNION ALL：</strong> UNION ALL同样用于合并查询结果集，但不去除重复的行。相比UNION，执行效率更高。</p>
<h2 id="如何快速定位慢sql" tabindex="-1"><a class="header-anchor" href="#如何快速定位慢sql"><span>如何快速定位慢SQL</span></a></h2>
<ol>
<li><strong>启用慢查询日志：</strong></li>
<li><strong>使用EXPLAIN分析执行计划：</strong></li>
<li><strong>检查索引使用情况：</strong></li>
<li><strong>分析查询语句：</strong></li>
</ol>
<h2 id="慢sql你是怎么优化的" tabindex="-1"><a class="header-anchor" href="#慢sql你是怎么优化的"><span>慢SQL你是怎么优化的？</span></a></h2>
<ol>
<li><strong>优化查询语句结构：</strong></li>
<li><strong>添加合适的索引：</strong></li>
<li><strong>使用覆盖索引:</strong></li>
<li><strong>避免全表扫描：</strong></li>
<li><strong>合理分页查询：</strong></li>
</ol>
<h2 id="索引失效的情况有哪些" tabindex="-1"><a class="header-anchor" href="#索引失效的情况有哪些"><span>索引失效的情况有哪些</span></a></h2>
<ol>
<li><strong>不满足索引列顺序：</strong></li>
<li><strong>使用函数或表达式：</strong></li>
<li><strong>字符串比较问题:</strong></li>
<li><strong>数据类型不匹配：</strong></li>
<li><strong>数据量过小：</strong></li>
<li><strong>使用NOT、&lt;&gt;、OR等非优化的逻辑操作符：</strong></li>
</ol>
<h2 id="说说你对数据库事务的理解" tabindex="-1"><a class="header-anchor" href="#说说你对数据库事务的理解"><span>说说你对数据库事务的理解</span></a></h2>
<p>数据库事务是指一系列数据库操作的逻辑单元，这些操作要么<strong>全部执行成功，要么全部回滚</strong>。以确保数据的一致性和完整性。
<strong>事务具备4大特性：原子性、一致性、隔离性、持久性。</strong>
<strong>原子性：</strong> 事务中的所有操作要么全部执行成功，要么全部回滚到事务开始前的状态。如果在事务执行期间发生错误，系统将回滚所有已执行的操作，以保持数据的一致性。
<strong>一致性：</strong> 事务的执行不会破坏数据库的完整性约束。在事务开始和结束时，数据库必须处于一直的状态。
<strong>隔离性：</strong> 事务的执行是相互隔离的，即每个事务对其他事务是透明的。并发执行的多个事务不会相互干扰，每个事务感知不到其他事务的存在。
<strong>持久性：</strong> 一旦事务提交成功，事务中的所有操作都必须持久化到数据库中。</p>
<h2 id="事务的隔离级别有哪些" tabindex="-1"><a class="header-anchor" href="#事务的隔离级别有哪些"><span>事务的隔离级别有哪些</span></a></h2>
<ol>
<li><strong>读未提交：</strong> 最低的隔离级别。事务可以读取到其他事务尚未提交的数据，可能出现脏读、不可重复读和幻读问题。</li>
<li><strong>读已提交(RC)：</strong> 事务只能读到已经提交的数据。但在同一事务中，多次读取同一行的数据结果可能会不一致，可能会出现不可重复读和幻读问题。</li>
<li><strong>可重复读(RR)：</strong> 在同一个事务内，多次读取同一行的数据结果始终保持一致。<strong>MySQL的默认隔离级别就是可重复读</strong>。通过使用MVCC机制来实现，在读操作期间不会看到其他事务的修改，有效地解决了不可重复读问题。</li>
<li><strong>串行化：</strong> 最高的隔离级别。事务串行执行，避免了脏读、不可重复读和幻读问题。但是并发性能较差，可能导致大量的锁竞争和资源争用。</li>
</ol>
<h2 id="说说你对mvcc的理解" tabindex="-1"><a class="header-anchor" href="#说说你对mvcc的理解"><span>说说你对MVCC的理解</span></a></h2>
<p>MVCC是一种并发控制策略，它在多个事务同时执行时，确保数据库的一致性和隔离性。MVCC通过为每个事务创建数据的不同版本，避免了锁竞争问题。
它的工作原理如下：</p>
<ul>
<li>每条数据行都有一个隐藏的版本号或时间戳，记录该行的创建或最后修改时间。</li>
<li>当事务开始，它会获取一个唯一的事务ID，作为其开始时间戳。</li>
<li>在读取数据时，事务只能访问在其开始时间戳之前已提交的数据。这个版本的数据在事务开始前就已经存在。</li>
<li>当事务更新数据，会创建新版本的数据，将更新后的数据写入新的数据行，并将事务ID与新版本关联。</li>
<li>其他事务可以继续访问旧版本的数据，不受正在进行的更新事务影响。这种机制被称为&quot;快照读&quot;。</li>
<li>当事务提交，其所有修改才对其他事务可见。此时，新版本的数据成为其他事务读取的数据。</li>
</ul>
<p>以上就是MVCC的工作原理。它是通过多个版本的数据来实现并发控制，提高了数据库的并发性能，并确保了事务之间的隔离性和数据一致性。</p>
<h2 id="undo-log是如何回滚事务的" tabindex="-1"><a class="header-anchor" href="#undo-log是如何回滚事务的"><span>Undo log是如何回滚事务的</span></a></h2>
<p>在数据库中，<strong>Undo log通常用于实现爱你事务的回滚操作</strong>。当事务执行更新操作时，数据库会将相应的旧数据记录在Undo log中，用于回滚事务时还原到事务开始前的状态，以下是Undo log回滚事务的一般步骤：、</p>
<p><strong>首先</strong>，获取事务的回滚指针或Undo Log的起始位置。
从Undo Log的末尾开始逆向扫描，按照事务的操作的逆序依次处理每个日志记录。
<strong>然后</strong>，针对INSERT操作，执行DELETE操作来撤销插入的数据。对于UPDATE操作，使用Undo Log中记录的旧值将数据还原到之前的状态。
在回滚过程中，对于已经提交的其他事务所做到修改需要跳过，只处理属于当前回滚事务的Undo Log记录。
按照逆序依次处理所有的日志记录，直到达到回滚指针为止或Undo Log的起始位置。
<strong>回滚完成后</strong>，清除或标记已回滚的Undo Log记录。</p>
<h2 id="说说主从复制的原理与延迟" tabindex="-1"><a class="header-anchor" href="#说说主从复制的原理与延迟"><span>说说主从复制的原理与延迟</span></a></h2>
<p>MySQL的主从复制原理如下：
首先，主库将变更写入binlog日志。
从库连接到主库后，有一个IO线程负责将<strong>主库的binlog日志</strong>复制到自己本地，并写入<strong>中继日志</strong>中。
然后，从库中有一个SQL线程会从中继日志中读取binlog，并执行其中的SQL内容，即在从库上再次执行一编。
以上就是主从复制额度原理。</p>
<p>主从延迟的原因有以下几种：</p>
<ol>
<li>主库的从库太多，主库需要将binlong日志传输到多个从库，导致复制延迟。</li>
<li>在从库执行的SQL中存在慢查询语句，会导致整体复制的进程的延迟。</li>
<li>如果主库的读写压力过大，会导致主库处理binlog的速度减慢，进而影响复制延迟。</li>
</ol>
<p>为了优化主从复制的延迟，可以采取以下措施：</p>
<ol>
<li>减少从库的数量，降低主库的负载，减少复制延迟。</li>
<li>优化慢查询语句，减少从库执行SQL的延迟。</li>
<li>对主库进行性能优化，减少主库的读写压力，提高binlog写入速度。</li>
</ol>
<h2 id="了解mysql锁升级吗" tabindex="-1"><a class="header-anchor" href="#了解mysql锁升级吗"><span>了解MySQL锁升级吗</span></a></h2>
<p><strong>MySQL锁升级是指在并发事务执行过程中，当某个事务无法满足当前所需的锁级别时，系统会自动将该事务的锁级别升级为更高几倍的锁。</strong></p>
<p>通常情况下，MySQL会根据事务的需求和操作的对象<strong>自动选择</strong>合适的锁级别。然而，在某些情况下，事务无法获取所需的所级别，就会触发升级。
例如以下两种常见的锁升级场景:</p>
<ol>
<li>当某个事务需要获取的是行级锁，但由于并发冲突或其他原因无法满足事务的要求时，系统会将该事务的锁级别升级为表级锁，从而保证数据的一致性和并发性能。</li>
<li>当某个事务操作的对象不符合行锁加锁规则，比如没有走索引或非唯一索引记录数达到一定数量，系统也会将该事务的所级别升级为表级锁。</li>
</ol>
<h2 id="mysql有那些高可用方案" tabindex="-1"><a class="header-anchor" href="#mysql有那些高可用方案"><span>MySQL有那些高可用方案</span></a></h2>
<ol>
<li><strong>主从复制：</strong> 主库负责处理写操作，并把数据变更记录到binlog日志。从库将主库的binlong复制到自己的中继日志，然后执行中继日志中的事件，以达到与主库数据一致的目的。当主库出现故障时，可以将从库提升为新的主库，实现服务的高可用。</li>
<li><strong>集群：</strong> MysQL集群是一个高可用、高性能的数据库集群解决方案。它使用了共享无关的架构，可以在节点之间自动分割和复制数据，实现了数据的高可用和高性能。</li>
</ol>
<h2 id="如何解决mysql死锁问题" tabindex="-1"><a class="header-anchor" href="#如何解决mysql死锁问题"><span>如何解决MySQL死锁问题</span></a></h2>
<p>MySQL在并发环境下可能会出现死锁问题。死锁是指两个或多个事务互相等待对方释放资源，导致无法继续执行的情况。</p>
<p>解决死锁问题的方法通常有以下集中：</p>
<ol>
<li><strong>调整事务隔离级别：</strong> 通过将事务隔离级别降低为读未提交（或读已提交，可以减少死锁的发生概率。但是要注意隔离级别的降低可能引发脏读、不可重复读等数据一致性问题，在选择时需要权衡利弊。</li>
<li><strong>优化查询和事务逻辑：</strong> 分析造成死锁的原因，优化查询语句和事务逻辑，尽量缩短事务持有锁的时间，减少死锁的可能性。比如按照相同的顺序获取锁、避免跨事务的循环依赖等。</li>
<li><strong>使用行级锁：</strong> 行级锁可以较小地限制锁的范围，从而减少死锁的可能性。将表的锁粒度调整为行级别，可以减少事务之间的冲突。</li>
<li><strong>调整合理的超时时间和重试机制：</strong> 当发生死锁时，可以设置适当的超时时间，在一定时间内尝试解锁操作。如果超过设定的时间仍未成功，则进行死锁处理，如终止较早请求的事务或进行回滚等。</li>
</ol>
<h2 id="mysql索引底层结构为什么要使用b-树" tabindex="-1"><a class="header-anchor" href="#mysql索引底层结构为什么要使用b-树"><span>MysQL索引底层结构为什么要使用B+树</span></a></h2>
<ol>
<li><strong>良好的平衡性：</strong></li>
<li><strong>顺序访问性：</strong></li>
<li><strong>存储效率：</strong></li>
<li><strong>支持高并发：</strong></li>
<li><strong>易于扩展和维护：</strong></li>
</ol>
<h2 id="说说你对分库分表的理解" tabindex="-1"><a class="header-anchor" href="#说说你对分库分表的理解"><span>说说你对分库分表的理解</span></a></h2>
<p>MySQL的分库分表拆分策略通常包括<strong>垂直拆分</strong>和<strong>水平拆分</strong>两种方式。</p>
<ul>
<li><strong>水平拆分：</strong></li>
<li><strong>垂直拆分：</strong></li>
</ul>
<h4 id="分库分表面临的问题和解决方案如下" tabindex="-1"><a class="header-anchor" href="#分库分表面临的问题和解决方案如下"><span>分库分表面临的问题和解决方案如下：</span></a></h4>
<ol>
<li><strong>数据一致性：</strong></li>
<li><strong>跨分片查询：</strong></li>
<li><strong>全局唯一性约束：</strong></li>
</ol>
<h2 id="高并发场景下-如何安全修改同一行数据" tabindex="-1"><a class="header-anchor" href="#高并发场景下-如何安全修改同一行数据"><span>高并发场景下，如何安全修改同一行数据</span></a></h2>
<ol>
<li><strong>乐观锁：在数据表中添加一个版本号（或者时间戳）字段，每次更新数据时都会检查该字段的值。</strong></li>
<li><strong>悲观锁：</strong></li>
<li><strong>分布式锁：</strong></li>
<li><strong>事务：</strong></li>
</ol>
<h2 id="数据cpu飙升-你会如何处理" tabindex="-1"><a class="header-anchor" href="#数据cpu飙升-你会如何处理"><span>数据CPU飙升，你会如何处理</span></a></h2>
<ol>
<li><strong>查询性能问题：</strong></li>
<li><strong>数据库连接问题：</strong></li>
<li><strong>锁和死锁问题：</strong></li>
<li><strong>配置问题：</strong></li>
<li><strong>资源竞争：</strong></li>
</ol>
<h2 id="一条sql的执行过程是怎样的" tabindex="-1"><a class="header-anchor" href="#一条sql的执行过程是怎样的"><span>一条SQL的执行过程是怎样的</span></a></h2>
<ol>
<li><strong>连接器：</strong></li>
<li><strong>查询缓存：</strong></li>
<li><strong>分析器：</strong></li>
<li><strong>优化器：</strong></li>
<li><strong>执行器：</strong></li>
<li><strong>存储引擎：</strong></li>
<li><strong>返回结果：</strong></li>
</ol>
<h2 id="分表后非分片键的查询、排序怎么处理" tabindex="-1"><a class="header-anchor" href="#分表后非分片键的查询、排序怎么处理"><span>分表后非分片键的查询、排序怎么处理</span></a></h2>
<ol>
<li><strong>联合查询:</strong></li>
<li><strong>扫描所有分表：</strong></li>
<li><strong>手动分页和排序：</strong></li>
<li><strong>使用全局索引：</strong></li>
</ol>
<h2 id="自增主键会遇到什么问题" tabindex="-1"><a class="header-anchor" href="#自增主键会遇到什么问题"><span>自增主键会遇到什么问题</span></a></h2>
<ol>
<li><strong>插入性能问题:</strong></li>
<li><strong>主键耗尽：</strong></li>
<li><strong>分布式系统问题：</strong></li>
</ol>
<h2 id="分库分表下如何实现精准分页" tabindex="-1"><a class="header-anchor" href="#分库分表下如何实现精准分页"><span>分库分表下如何实现精准分页</span></a></h2>
<p>要想实现精准分页就需要解决两个主要问题：<strong>跨分片和跨库的数据访问</strong></p>
<p><strong>跨分片：</strong> 常见的方法是使用<strong>记录游标分页</strong>。这种方法会在每个分片中<strong>记录上一页或下一页的分页表示</strong>，比如记录上一页或下一个的最后一条记录的<strong>主键</strong>。
然后，当执行分页查询时，根据游标进行定位，从而实现精准分页。但是需要在分片中<strong>维护额外的索引或元数据信息</strong>。</p>
<p><strong>跨库：</strong> 常见的方法是通过<strong>数据同步</strong>或者<strong>查询路由</strong>来实现跨库的数据分页。
<strong>数据同步：</strong> 将分片中的数据复制到一个统一的主库中，然后在主库上执行分页操作。
<strong>查询路由：</strong> 在查询时根据分页条件将请求发送到对应的分片或库汇总，然后在各个分片中执行分页操作，最后奖结果合并返回给客户端。
这种方法可以<strong>减少数据复制的开销</strong>，但是会<strong>增加系统的复杂度和维护成本</strong>。</p>
<h2 id="where-1-1-会不会影响性能" tabindex="-1"><a class="header-anchor" href="#where-1-1-会不会影响性能"><span>where 1=1 会不会影响性能？</span></a></h2>
<p><strong>不会</strong>
MySQL5.7后，有一个所谓的（常量折叠优化）可以在编译器消除重言式表达式（任何时候为true的结果），where 1==1就会被优化器识别并优化掉。</p>
<h2 id="什么数据用hash存储" tabindex="-1"><a class="header-anchor" href="#什么数据用hash存储"><span>什么数据用hash存储</span></a></h2>
<p>哈希索引只能做等于查找，查询复杂度都是O(1)。
但是hash结果不支持范围查询，因为哈希算法将输入映射到一定固定大小的哈希值，不同的输入可能会产生相同的哈希值（哈希碰撞）。因此，哈希表不保留输入数据的顺序，所以不支持范围查询。</p>
</div></template>


